﻿namespace MobileTrack.Core.Tests.Data
{
    using System;
    using System.Data.Entity;
    using System.Linq;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using MobileTrack.Core.Data;
    using MobileTrack.Core.Model;

    [TestClass]
    public class MobileTrackRepositoriesFixture
    {
        private const string ConnectionStringName = "MobileTrackDbTests";

        [TestInitialize]
        public void TestInitialize()
        {
            var context = CreateContext();
            context.Database.Delete();
        }

        [TestMethod]
        public void ShouldAddAndDeleteSucursales()
        {
            Action<Sucursal> initialize =
                sucursal =>
                {
                    sucursal.Nombre = "Sucursal Nombre Test";
                    sucursal.Codigo = "Sucursal Codigo Test";
                };

            using (var repositories = new MobileTrackRepositories(CreateContext()))
            {
                TestSingleAddAndDelete(repositories, repositories.Sucursales, initialize);
                TestMultipleAddAndDelete(repositories, repositories.Sucursales, initialize);
            }
        }

        [TestMethod]
        public void ShouldAddAndDeleteProveedores()
        {
            Action<Proveedor> initialize =
                proveedor =>
                {
                    proveedor.Nombre = "Proveedor Nombre Test";
                };

            using (var repositories = new MobileTrackRepositories(CreateContext()))
            {
                TestSingleAddAndDelete(repositories, repositories.Proveedores, initialize);
                TestMultipleAddAndDelete(repositories, repositories.Proveedores, initialize);
            }
        }

        [TestMethod]
        public void ShouldAddAndDeleteMarcas()
        {
            Action<Marca> initialize =
                marca =>
                {
                    marca.Nombre = "Marca Nombre Test";
                    marca.Proveedor = new Proveedor { Nombre = "Proveedor Nombre Test" };
                };

            using (var repositories = new MobileTrackRepositories(CreateContext()))
            {
                TestSingleAddAndDelete(repositories, repositories.Marcas, initialize);
                TestMultipleAddAndDelete(repositories, repositories.Marcas, initialize);
            }
        }

        [TestMethod]
        public void ShouldAddAndDeleteAbonos()
        {
            Action<Abono> initialize =
                abono =>
                {
                    abono.Descripcion = "Abono Descripcion Test";
                    abono.Operador = new Marca
                        {
                            Nombre = "Marca Nombre Test",
                            Proveedor = new Proveedor { Nombre = "Proveedor Nombre Test" }
                        };
                };

            using (var repositories = new MobileTrackRepositories(CreateContext()))
            {
                TestSingleAddAndDelete(repositories, repositories.Abonos, initialize);
                TestMultipleAddAndDelete(repositories, repositories.Abonos, initialize);
            }
        }

        [TestMethod]
        public void ShouldAddAndDeleteCelulares()
        {
            Action<Celular> initialize =
                celular =>
                {
                    celular.Descripcion = "Celular Descripcion Test";
                    celular.Marca = new Marca
                        {
                            Nombre = "Marca Nombre Test",
                            Proveedor = new Proveedor { Nombre = "Proveedor Nombre Test" }
                        };
                };

            using (var repositories = new MobileTrackRepositories(CreateContext()))
            {
                TestSingleAddAndDelete(repositories, repositories.Celulares, initialize);
                TestMultipleAddAndDelete(repositories, repositories.Celulares, initialize);
            }
        }

        [TestMethod]
        public void ShouldAddAndDeleteSeguimientos()
        {
            Action<Seguimiento> initialize =
                seguimiento =>
                {
                    seguimiento.Comprobante = "Seguimiento Comprobante Test";
                    seguimiento.Celular = new Celular
                        {
                            Descripcion = "Celular Descripcion Test",
                            Marca = new Marca
                            {
                                Nombre = "Marca Nombre Test",
                                Proveedor = new Proveedor { Nombre = "Proveedor Nombre Test" }
                            }
                        };
                    seguimiento.Sucursal = new Sucursal
                        {
                            Nombre = "Sucursal Nombre Test",
                            Codigo = "Sucursal Codigo Test"
                        };
                };

            using (var repositories = new MobileTrackRepositories(CreateContext()))
            {
                TestSingleAddAndDelete(repositories, repositories.Seguimientos, initialize);
                TestMultipleAddAndDelete(repositories, repositories.Seguimientos, initialize);
            }
        }

        [TestMethod]
        public void ShouldAddAndDeleteVetas()
        {
            Action<Venta> initialize =
                venta =>
                {
                    var marca = new Marca
                        {
                            Nombre = "Marca Nombre Test",
                            Proveedor = new Proveedor { Nombre = "Proveedor Nombre Test" }
                        };
                    var celular = new Celular
                        {
                            Descripcion = "Celular Descripcion Test",
                            Marca = marca
                        };

                    venta.Celular = celular;
                    venta.Seguimiento = new Seguimiento
                        {
                            Comprobante = "Seguimiento Comprobante Test",
                            Celular = celular,
                            Sucursal = new Sucursal
                                {
                                    Nombre = "Sucursal Nombre Test",
                                    Codigo = "Sucursal Codigo Test"
                                }
                        };
                    venta.Abono = new Abono
                        {
                            Descripcion = "Abono Descripcion Test",
                            Operador = marca
                        };
                };

            using (var repositories = new MobileTrackRepositories(CreateContext()))
            {
                TestSingleAddAndDelete(repositories, repositories.Ventas, initialize);
                TestMultipleAddAndDelete(repositories, repositories.Ventas, initialize);
            }
        }

        private static MobileTrackContext CreateContext()
        {
            Database.SetInitializer(
                new MigrateDatabaseToLatestVersion<MobileTrackContext, TestConfiguration>(ConnectionStringName));

            return new MobileTrackContext(ConnectionStringName);
        }

        private static TEntity CreateInstance<TEntity>(Action<TEntity> initialize = null)
            where TEntity : BaseEntity
        {
            var entityInstance = Activator.CreateInstance<TEntity>();

            if (initialize != null)
            {
                initialize(entityInstance);
            }

            return entityInstance;
        }

        private void TestSingleAddAndDelete<TEntity>(IRepositories repositories, IRepository<TEntity> repository, Action<TEntity> initialize = null)
            where TEntity : BaseEntity
        {
            // Add item
            var item = CreateInstance<TEntity>(initialize);
            repository.Add(item);
            repositories.SaveChanges();
            Assert.AreEqual(1, repository.All.Count());

            // Delete item
            item = repository.All.Single();
            repository.Delete(item.Id);
            repositories.SaveChanges();
            Assert.AreEqual(0, repository.All.Count());

            // Add item
            item = CreateInstance<TEntity>(initialize);
            repository.Add(item);
            repositories.SaveChanges();
            Assert.AreEqual(1, repository.All.Count());

            // Delete item
            item = repository.All.Single();
            repository.Delete(item);
            repositories.SaveChanges();
            Assert.AreEqual(0, repository.All.Count());
        }

        private void TestMultipleAddAndDelete<TEntity>(IRepositories repositories, IRepository<TEntity> repository, Action<TEntity> initialize = null)
            where TEntity : BaseEntity
        {
            // Add multiple items
            var items = new[] { CreateInstance<TEntity>(initialize), CreateInstance<TEntity>(initialize), CreateInstance<TEntity>(initialize) };
            repository.AddRange(items);
            repositories.SaveChanges();
            Assert.AreEqual(3, repository.All.Count());

            // Delete multiple items
            items = repository.All.ToArray();
            repository.DeleteRange(items);
            repositories.SaveChanges();
            Assert.AreEqual(0, repository.All.Count());
        }
    }
}
